package com.remoter.api.context.support;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.remoter.api.consumer.IConsumerService;
import com.remoter.api.context.IContextService;
import com.remoter.api.exception.RemoterException;
import com.remoter.api.protocol.support.RemoterRequest;
import com.remoter.api.protocol.support.RemoterResponse;
import com.remoter.api.transport.IClient;

public class ContextInvocationHandler implements InvocationHandler{
	
	private static final Logger logger = LoggerFactory.getLogger(ContextInvocationHandler.class);
	
	private final Importer importer;
	private final IContextService contextService;
	private final IConsumerService consumerService;
	private final boolean async;
	
	public ContextInvocationHandler(IContextService contextService,IConsumerService consumerService,Importer importer){
		this.contextService = contextService;
		this.importer = importer;
		this.consumerService = consumerService;
		this.async = this.importer.isAsync();
	}
	
	@Override
	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
		String methodName = method.getName();
		Class<?>[] parameterTypes = method.getParameterTypes();
		if(method.getDeclaringClass() == Object.class){
			return method.invoke(proxy,args);
		}
		if("toString".equals(methodName) && parameterTypes.length == 0){
			return proxy.toString();
		}
		if("hashCode".equals(methodName) && parameterTypes.length == 0){
			return proxy.hashCode();
		}
		if("equals".equals(methodName) && parameterTypes.length == 1){
			return proxy.equals(args[1]);
		}
		RemoterRequest remoterRequest = new RemoterRequest();
		remoterRequest.setServiceBeanName(this.importer.getBean());
		remoterRequest.setServiceClass(this.importer.getType());
		remoterRequest.setServiceMethodName(methodName);
		remoterRequest.setServiceParamObjects(args);
		remoterRequest.setServiceParamTypes(parameterTypes);
		try{
			this.importer.setMethod(methodName);
			Exporter temp = this.contextService.select(this.importer);
			if(null == temp){
				throw new RemoterException("provider client not found");
			}
			logger.debug("get client for :" + temp.getSocketAddress());
			IClient client = this.consumerService.getClient(temp.getSocketAddress(),true);
			if(null == client){
				throw new RemoterException("provider client not found");
			}
			if(!client.isAvailable()){
				throw new RemoterException("provider client is closed");
			}
			RemoterResponse remoterResponse = client.sendRemoterRequest(remoterRequest);
			if(remoterResponse.hasException()){
				throw new RemoterException(remoterResponse.getException());
			}
			if(this.async){
				return null;
			}else{
				return remoterResponse.getData();
			}
		}catch(Exception e){
			throw new RemoterException(e.getMessage(),e);
		}
	}
	
}